import 'package:flutter/material.dart';

class RectTabIndicator extends Decoration {
  const RectTabIndicator({
    this.borderSide = const BorderSide(width: 1.0, color: Colors.white),
    this.insetsGeometry = EdgeInsets.zero,
    this.gradient,
    this.indicatorSize = 4,
    this.offset = 10,
    this.isPin = false,
    this.pinSize = 20,
  });

  final BorderSide borderSide;

  final EdgeInsetsGeometry insetsGeometry;

  final Gradient? gradient;

  final double indicatorSize;

  final double offset;

  final bool isPin;

  final double pinSize;

  @override
  Decoration? lerpFrom(Decoration? a, double t) {
    if (a is RectTabIndicator) {
      return RectTabIndicator(
          borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
          insetsGeometry:
              EdgeInsetsGeometry.lerp(a.insetsGeometry, insetsGeometry, t)!);
    }
    return super.lerpFrom(a, t);
  }

  @override
  Decoration? lerpTo(Decoration? b, double t) {
    if (b is RectTabIndicator) {
      return RectTabIndicator(
          borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
          insetsGeometry:
              EdgeInsetsGeometry.lerp(insetsGeometry, b.insetsGeometry, t)!);
    }
    return super.lerpTo(b, t);
  }

  @override
  UnderlinePainter createBoxPainter([VoidCallback? onChanged]) {
    return UnderlinePainter(this, onChanged);
  }

  Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
    final Rect indicator =
        insetsGeometry.resolve(textDirection).deflateRect(rect);
    return Rect.fromLTWH(
      indicator.left,
      indicator.bottom - borderSide.width,
      indicator.width,
      borderSide.width,
    );
  }

  @override
  Path getClipPath(Rect rect, TextDirection textDirection) {
    return Path()..addRect(_indicatorRectFor(rect, textDirection));
  }
}

class UnderlinePainter extends BoxPainter {
  UnderlinePainter(this.decoration, VoidCallback? onChanged) : super(onChanged);

  final RectTabIndicator decoration;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    assert(configuration.size != null);

    var pinTrans = (configuration.size!.width - decoration.pinSize) / 2;
    offset = offset.translate(
      decoration.isPin ? pinTrans : 0,
      configuration.size!.height - decoration.indicatorSize - decoration.offset,
    );

    Size mConfiguration = Size(
      decoration.isPin ? decoration.pinSize : configuration.size!.width,
      decoration.indicatorSize,
    );
    final Rect rect1 = offset & mConfiguration;
    final RRect rRectOut = RRect.fromRectAndRadius(
      rect1,
      const Radius.circular(8),
    );

    Shader shader;
    if (decoration.gradient != null) {
      shader = decoration.gradient!.createShader(rect1);
    } else {
      shader = const LinearGradient(
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
        colors: [Color(0x3238ABFF), Color(0xFF1A72FE)],
      ).createShader(rect1);
    }

    canvas.drawRRect(
      rRectOut,
      Paint()
        ..style = PaintingStyle.fill
        ..shader = shader,
    );
  }
}

/// 圆角
class RoundTabIndicator extends Decoration {
  const RoundTabIndicator({
    this.insetsGeometry = EdgeInsets.zero,
    this.gradient,
    this.offset = 10,
  });

  final EdgeInsetsGeometry insetsGeometry;

  final Gradient? gradient;

  final double offset;

  @override
  Decoration? lerpFrom(Decoration? a, double t) {
    if (a is RoundTabIndicator) {
      return RoundTabIndicator(
          insetsGeometry:
              EdgeInsetsGeometry.lerp(a.insetsGeometry, insetsGeometry, t)!);
    }
    return super.lerpFrom(a, t);
  }

  @override
  Decoration? lerpTo(Decoration? b, double t) {
    if (b is RoundTabIndicator) {
      return RoundTabIndicator(
          insetsGeometry:
              EdgeInsetsGeometry.lerp(insetsGeometry, b.insetsGeometry, t)!);
    }
    return super.lerpTo(b, t);
  }

  @override
  RoundPainter createBoxPainter([VoidCallback? onChanged]) {
    return RoundPainter(this, onChanged);
  }

  Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
    final Rect indicator =
        insetsGeometry.resolve(textDirection).deflateRect(rect);
    return Rect.fromLTWH(
      indicator.left,
      indicator.bottom,
      indicator.width,
      indicator.height,
    );
  }

  @override
  Path getClipPath(Rect rect, TextDirection textDirection) {
    return Path()..addRect(_indicatorRectFor(rect, textDirection));
  }
}

class RoundPainter extends BoxPainter {
  RoundPainter(this.decoration, VoidCallback? onChanged) : super(onChanged);

  final RoundTabIndicator decoration;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    assert(configuration.size != null);

    Size mConfiguration = Size(
      configuration.size!.width,
      configuration.size!.height,
    );
    final Rect rect1 = offset & mConfiguration;
    final RRect rRectOut = RRect.fromRectAndRadius(
      rect1,
      const Radius.circular(8),
    );

    Shader shader;
    if (decoration.gradient != null) {
      shader = decoration.gradient!.createShader(rect1);
    } else {
      shader = const LinearGradient(
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
        colors: [Color(0xFF00D371), Color(0xFF00D371)],
      ).createShader(rect1);
    }

    canvas.drawRRect(
      rRectOut,
      Paint()
        ..style = PaintingStyle.fill
        ..shader = shader,
    );
  }
}
